package com.blacktech.dbu.auth.security;

import com.blacktech.dbu.auth.entity.DbuUser;
import com.blacktech.dbu.auth.service.UserService;
import com.blacktech.dbu.core.dict.UserType;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.Optional;

/**
 * 角色权限拦截器
 * 处理@RolePermission注解的权限验证，基于UserType权限级别判断
 *
 * @author Yanyunsong
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RolePermissionInterceptor implements HandlerInterceptor {

    private final UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod handlerMethod)) {
            return true;
        }

        Method method = handlerMethod.getMethod();
        Class<?> targetClass = method.getDeclaringClass();

        // 检查类级别的角色权限注解
        RolePermission classAnnotation = targetClass.getAnnotation(RolePermission.class);
        // 检查方法级别的角色权限注解
        RolePermission methodAnnotation = method.getAnnotation(RolePermission.class);
        // 优先使用方法级别的注解
        RolePermission permissionAnnotation = methodAnnotation != null ? methodAnnotation : classAnnotation;
        // 如果没有角色权限注解，直接通过
        if (permissionAnnotation == null) {
            return true;
        }

        log.debug("检查角色权限: {}.{}", targetClass.getSimpleName(), method.getName());
        // 获取当前认证用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !StringUtils.hasText(authentication.getName())) {
            log.warn("用户未登录，拒绝访问");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"message\":\"用户未登录\"}");
            return false;
        }

        String username = authentication.getName();
        log.debug("检查用户 {} 的角色权限: {}.{}", username, targetClass.getSimpleName(), method.getName());

        // 检查权限
        if (!hasPermission(authentication, permissionAnnotation)) {
            log.warn("用户 {} 权限不足，拒绝访问", username);
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(String.format("{\"code\":403,\"message\":\"%s\"}", permissionAnnotation.message()));
            return false;
        }

        log.debug("用户 {} 角色权限检查通过", username);
        return true;
    }

    /**
     * 检查用户权限
     */
    private boolean hasPermission(Authentication authentication, RolePermission annotation) {
        try {
            // 获取用户信息
            String username = authentication.getName();
            Optional<DbuUser> user = userService.getUserByUsername(username);
            if (user.isEmpty()) {
                log.warn("用户 {} 类型未找到", username);
                return false;
            }
            UserType userType = user.get().getUserType();
            if (userType == UserType.SUPER_ADMIN) {
                log.debug("用户 {} 为超级管理员，权限级别检查通过", username);
                return true;
            }
            int userPermissionLevel = userType.getPermissionLevel();
            int requireLevel = annotation.required();
            boolean hasPermission = userPermissionLevel <= requireLevel;
            log.debug("用户 {} 权限级别检查: 用户级别={}, 要求级别={}, 结果={}", username, userPermissionLevel, requireLevel, hasPermission);
            return hasPermission;
        } catch (Exception e) {
            log.error("权限级别检查失败", e);
            return false;
        }
    }
}